#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>
#include <libio.h>
#include "q_utils.h"

//
/* typedef struct
{
  Elf64_Word     sh_name; // 区间名（字符串表索引）。
  Elf64_Word     sh_type; // 区间类型。
  Elf64_Xword    sh_flags; // 区间标志。
  Elf64_Addr     sh_addr; // 区间虚拟地址。
  Elf64_Off  sh_offset; // 区间文件偏移。
  Elf64_Xword    sh_size; // 区间大小（单位：字节）。
  Elf64_Word     sh_link;
  Elf64_Word     sh_info;
  Elf64_Xword    sh_addralign;
  Elf64_Xword    sh_entsize; // 这个会在下面 lssym 的时候解释。
} Elf64_Shdr; 

*/


elf_file *
open_elf(char * file_name){
	FILE * fp;
	elf_file * elf_file_p = (elf_file*)malloc(sizeof(elf_file));
	elf_file_p->elf_header = NULL;
	unsigned char e_ident[EI_NIDENT];

	if((fp = fopen(file_name, "r+")) == NULL){
		fprintf(stderr, "No such file %s \n", file_name);
		return EXIT_FAILURE;
	}
	if (fread(e_ident, 1, EI_NIDENT, fp) != EI_NIDENT){
		fprintf(stderr, "%s\n", "Incomplete ELF Identification!");
		return EXIT_FAILURE;
	}
	printf("ok ");

	if (memcmp(e_ident, ELFMAG, SELFMAG) != 0){
		fprintf(stderr, "%s\n", "Bad ELF Magic Number!");
		return EXIT_FAILURE;
	}

	if (e_ident[EI_CLASS] != ELFCLASS64 || e_ident[EI_DATA] != ELFDATA2LSB){
		fprintf(stderr, "%s\n", "Only supported ELF64 LE!");
		return EXIT_FAILURE;
	}

	//Elf64_Ehdr * header = (Elf64_Ehdr*) malloc(sizeof(header));
	Elf64_Ehdr  header ;
	// back to file start point
	//
	fseek(fp, 0, SEEK_SET);
	if(fread(&header, 1, sizeof header , fp ) != sizeof header ){
		fprintf(stderr, "%s\n", "Incompleted ELF64 header");
		return EXIT_FAILURE;
	}
//	memcpy(elf_file_p->elf_header, header, sizeof header);
  elf_file_p->elf_header = &header;
	elf_file_p->elf_fp =  fp;	
	return elf_file_p;
}


Elf64_Shdr *
read_sh(elf_file * elf){
	Elf64_Ehdr  header = *(elf->elf_header);
	FILE * fp = elf->elf_fp;
	size_t size = header.e_shnum * header.e_shentsize;
	Elf64_Shdr * section_header_table = malloc(size);
	if (section_header_table == NULL){
		perror("malloc");
		return EXIT_FAILURE;
	}

	Elf64_Shdr shstrtab = section_header_table[header.e_shstrndx];
	size = shstrtab.sh_size;
	// malloc mem
	char *section_header_string_table = malloc(size);
	if(section_header_string_table == NULL){
		perror("malloc");
		return EXIT_FAILURE;
	}

	fseek(fp, shstrtab.sh_offset, SEEK_SET);
	if (fread(section_header_string_table, 1, size, fp) != size){
		perror("Incomplted Section table");
		return EXIT_FAILURE;
	}	
	printf("%s\n", "number offset     size   entsize   name");
	for (unsigned num = 0; num < header.e_shnum; num += 1) {
		Elf64_Shdr section_header = section_header_table[num];
    char *name = section_header_string_table + section_header.sh_name;
    printf("%4u %8llx %8llx %8llx %s\n",
      num, section_header.sh_offset,
      section_header.sh_size, section_header.sh_entsize,
      name);
	}
	return section_header_table;
}

int
main(int argc, char * argv[]){
	fprintf(stdout, "%s will be opened !\n", argv[1] );
	elf_file * elf = open_elf(argv[1]);
	if(elf->elf_header ==NULL){
		fprintf(stderr, "open elf failed\n");
	}
	read_sh(elf);
	return EXIT_SUCCESS;
}
